#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "chan.h"

chan_t *chan_open(char *ip, uint16_t port)
{
	int fd, ret;	
	struct sockaddr_in dest;
	chan_t *chan;

	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	assert(fd > 0);

	dest.sin_family = AF_INET;
	dest.sin_addr.s_addr= inet_addr(ip);
	dest.sin_port = htons(port);
	ret = connect(fd, (struct sockaddr*)&dest, sizeof(dest));
	assert(ret == 0);
	chan = (chan_t *)malloc(sizeof(chan_t));
	chan->fd = fd;
	return chan;

}

int	chan_send(chan_t *chan, uint8_t *data, int len)
{
	int	ret;

	ret = send(chan->fd, data, len, 0);
	return ret;
}

int	chan_recv(chan_t *chan, uint8_t *buf, int len)
{
	int	ret;

	ret = recv(chan->fd, buf, len, 0);
	return ret;
}

int	chan_recv2(chan_t *chan, uint8_t *buf, int len)
{
	int	ret, recved = 0;

	while(recved < len)
	{
		ret = recv(chan->fd, buf + recved, len - recved, 0);
		if(ret > 0) {
			recved += ret;
		}
		else{
			return -1;
		}
	}
	return recved;
}

void	chan_close(chan_t *chan)
{
	close(chan->fd);
}

chan_t	*chan_listen(char *ip, uint16_t port)
{
	int			fd, one=1, ret;
	struct sockaddr_in	service;
	chan_t			*chan;

	fd = socket(AF_INET, SOCK_STREAM, 0);
	assert(fd > 0);

	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));

	service.sin_family = AF_INET;
	service.sin_addr.s_addr = inet_addr(ip); 
	service.sin_port = htons(port); 
	ret = bind(fd, (struct sockaddr*)&service, sizeof(service));
	assert(ret == 0);
	ret = listen(fd, 128);
	assert(ret == 0);
	
	chan = (chan_t *)malloc(sizeof(chan_t));
	chan->fd = fd;
	return chan;
}

chan_t	*chan_accept(chan_t *chan)
{
	int	fd;
	chan_t	*nc;

	fd = accept(chan->fd, 0, 0);
	assert(fd > 0);

	nc = (chan_t *)malloc(sizeof(chan_t));
	nc->fd = fd;
	return nc;
}
